﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Reflection;
using System.Web.Caching;

namespace TSL.Utility
{
    internal sealed class jQueryProcessor
    {
        public static string AjaxInvokeParam = "AjaxInvoke";
        public static string AjaxInvokeValue = "1";
        public static string ResponseCharset = "UTF-8";

        private HttpContext context = null;

        internal string GetMethodName()
        {
            if ((this.context != null) && (this.context.Request["_method"] != null))
            {
                return this.context.Request["_method"];
            }
            return null;
        }

        internal void HandleException(string message)
        {
            Results res = new Results();
            res.Result = -1;
            res.Error = "系统错误：" + message;
            if (this.context.Request.AcceptTypes.Contains("text/xml"))
            {
                this.context.Response.Write(TSL.Utility.SerializerUtility.XmlSerializer(res));
            }
            else
            {
                this.context.Response.ContentType = "application/json, text/javascript, */*";
                this.context.Response.Write(TSL.Utility.SerializerUtility.JsonSerializer(res));
            }
        }

        public void RenderClientScript(Type type)
        {
            if (this.context.Cache[type.AssemblyQualifiedName] != null)
            {
                this.context.Response.Write((string)this.context.Cache[type.AssemblyQualifiedName]);
            }
            else
            {
                if (!TSL.Common.HttpHelp.getIni())
                {
                    HandleException("执行方法nulRunslt时错误！");
                }

                MethodInfo[] typea = type.GetMethods();
                var methodinfo = type.GetMethods().Where(t =>
                {
                    var attrs = t.GetCustomAttributes(typeof(jQueryInvokeMethodAttribute), false);
                    if (attrs != null && attrs.Length > 0)
                        return true;
                    return false;
                }).ToList();


                if (methodinfo != null && methodinfo.Count > 0)
                {
                    System.Text.StringBuilder sb = new StringBuilder();
                    sb.Append("window.defaultAjaxOption={type:'GET',cache:false, dataType:'text'};");
                    sb.AppendFormat(" window.{0}=function(){{}}; ", type.Name);
                    methodinfo.ForEach(t =>
                    {
                        var parameters = t.GetParameters().Select(p => p.Name).ToArray();
                        sb.AppendFormat(" {2}.{0} = function ({1} ajaxOption) {{", t.Name, parameters.Count() > 0 ? string.Join(",", parameters) + "," : "", type.Name);
                        sb.Append("if(ajaxOption==null||typeof ajaxOption=='undefined'){ajaxOption={};};");
                        var url = context.Request.RawUrl.IndexOf("?") == -1 ? context.Request.RawUrl : context.Request.RawUrl.Substring(0, context.Request.RawUrl.IndexOf("?"));
                        sb.AppendFormat("ajaxOption.url = '{0}';", url);
                        var data = "''";
                        if (parameters.Count() > 0)
                        {
                            data = (string.Join(" ", parameters.Select(p => string.Format("'&{0}=' + {0}+", p)).ToArray()));
                            data = data.TrimEnd('+');
                        }
                        sb.AppendFormat("ajaxOption.data = '_method={1}&rn={4}&{2}={3}'+{0};", data, t.Name, AjaxInvokeParam, AjaxInvokeValue, Guid.NewGuid().ToString());

                        sb.Append("ajaxOption= jQuery.extend(window.defaultAjaxOption,ajaxOption);");
                        sb.Append("jQuery.ajax(ajaxOption);};");
                    });
                    CacheDependency dependencies = new CacheDependency(type.Assembly.Location);
                    this.context.Cache.Add(type.AssemblyQualifiedName, sb.ToString(), dependencies, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
                    this.context.Response.Write(sb.ToString());
                }
            }
        }

        public void RegisterAjaxInvokeEvent(Type type, MethodInfo methodinfo)
        {

            var Request = this.context.Request;
            var Response = this.context.Response;
            Response.Charset = ResponseCharset;
            Response.ContentType = string.Join(",", Request.AcceptTypes);
            var param = methodinfo.GetParameters();
            object[] objs = new object[param.Length];
            var i = 0;
            param.ToList().ForEach(t =>
            {
                objs[i++] = Convert.ChangeType(Request[t.Name], t.ParameterType);
            });


            var obj = new object();
            if (methodinfo.IsStatic)
            {
                try
                {
                    obj = methodinfo.Invoke(null, objs);
                }
                catch
                {
                    HandleException("执行方法" + methodinfo.Name + "时错误！");
                    return;
                }
            }
            else
            {
                try
                {
                    var obj3 = Activator.CreateInstance(type, new object[0]);
                    if (obj3 != null)
                    {
                        obj = methodinfo.Invoke(obj3, objs);
                    }
                }
                catch
                {
                    HandleException("执行方法" + methodinfo.Name + "时错误！");
                    return;
                }
            }

            if (obj != null)
            {
                //序列化
                if (!obj.GetType().IsValueType && obj.GetType() != typeof(string))
                {
                    if (Request.AcceptTypes.Contains("text/xml"))
                    {
                        Response.Write(TSL.Utility.SerializerUtility.XmlSerializer(obj));
                    }
                    else if (Request.AcceptTypes.Contains("application/json"))
                    {
                        Response.ContentType = "application/json, text/javascript, */*";
                        Response.Write(TSL.Utility.SerializerUtility.JsonSerializer(obj));
                    }
                    else
                    {
                        Response.Write(obj);
                    }

                }
                else
                {
                    Response.Write(obj);
                }
            }
        }

        internal void InitializeContext(ref HttpContext context)
        {
            this.context = context;
        }
    }
}
